/*
 * Copyright (c) 2007-2008, Thomas Krause (tho.krause@gmail.com)
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of gidoo nor the names of its contributors may be used to
 *       endorse or promote products derived from this software without specific
 *       prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.gidoo.cms.data;

import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
/**
 * Describes a unique folder. Each folder belongs to a parent folder and a
 * section. In the CMS the URL is a certain path in the folder-tree pointing to
 * one folder. Each folder may contain a (published) page and old versions or 
 * pages that are not published yet.
 * 
 * @see Page
 * @author <a href="mailto:tho.krause@gmail.com">Thomas Krause</a>
 */
@Entity
@Table(uniqueConstraints={
  @UniqueConstraint(columnNames={"name", "parent_id", "section_id"}),
  @UniqueConstraint(columnNames={"position", "parent_id", "section_id"})})
public class Folder implements Serializable 
{
  
  private long id;

  private String name;
  
  private Folder parent;
  
  private CMSSection section;

  private int position;
  
  private Page publishedPage;
  
  private Page pageWaitingForPublisher;
  
  private List<Page> history;
  
  private List<Resource> resources;
  
  /** Set the unique ID. */
  public void setId(long id)
  {
    this.id = id;
  }

  /** Get the unique ID. */
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  public long getId()
  {
    return id;
  }

  /** 
   * Get the name. The URL of a request is equivalent to the path in the folder
   * tree with this item as the leaf. The name is part of the URL and represents
   * this folder. The name is unique for all children of a folder.
   */
  @Column(nullable=false)
  public String getName()
  {
    return name;
  }
  /** 
   * Set the name. The URL of a request is equivalent to the path in the folder
   * tree with this item as the leaf. The name is part of the URL and represents
   * this folder. The name is unique for all children of a folder.
   */
  public void setName(String name)
  {
    if(name != null)
    {
      this.name = name.replace('/', '_');
    }
    else
    {
      this.name = null;
    }
  }
  
  /**
   * Get the parent of the folder.
   * @return The unique parent or null if this folder is the root.
   */
  @ManyToOne
  @Column(nullable=false)
  public Folder getParent()
  {
    return parent;
  }
  /**
   * Set the parent of the folder.
   * @param parent The unique parent or null if this folder is the root.
   */
  public void setParent(Folder parent)
  {
    this.parent = parent;
  }

  
  /**
   * Each folder belongs to a section. This is a shorthand reference to tha section.
   */
  @ManyToOne
  @Column(nullable=false)
  public CMSSection getSection()
  {
    return section;
  }
  
  /**
   * Each folder belongs to a section. This is a shorthand reference to tha section.
   */
  public void setSection(CMSSection section)
  {
    this.section = section;
  }

  /**
   * Get the history of all published pages.
   */
  @OneToMany(cascade={CascadeType.REMOVE, CascadeType.PERSIST, CascadeType.MERGE})
  public List<Page> getHistory()
  {
    return history;
  }
  /**
   * Set the history of all published pages.
   */
  public void setHistory(List<Page> history)
  {
    this.history = history;
  }

  /**
   * Get the page which has been edited but not been accepted by a publisher yet.
   */
  @OneToOne(cascade=CascadeType.ALL)
  public Page getPageWaitingForPublisher()
  {
    return pageWaitingForPublisher;
  }
  
  /**
   * Set the page which has been edited but not been accepted by a publisher yet.
   */
  public void setPageWaitingForPublisher(Page pageWaitingForPublisher)
  {
    this.pageWaitingForPublisher = pageWaitingForPublisher;
  }

  /** 
   * Get the published page as it is presented to the user.
   * 
   * @return The page or null if not existant.
   */
  @OneToOne(cascade=CascadeType.REMOVE)
  public Page getPublishedPage()
  {
    return publishedPage;
  }
  /** 
   * Set the published page as it is presented to the user.
   * 
   * @param publishedPage The page or null if not existant.
   */
  public void setPublishedPage(Page publishedPage)
  {
    this.publishedPage = publishedPage;
  }

  /**
   * Returns the position of this folder in the list of children of the parent
   * folder. The first folder will get a 0, the second a 1 and so on.
   * The position has to be unique for all children of the same parent.
   */
  @Column(nullable=false)
  public int getPosition()
  {
    return position;
  }
  
  /**
   * Set the position of this folder in the list of children of the parent
   * folder. The first folder will get a 0, the second a 1 and so on.
   * The position has to be unique for all children of the same parent.
   */
  public void setPosition(int position)
  {
    this.position = position;
  }

  /**
   * Returns the resources which belong to this folder.
   */
  @OneToMany(mappedBy = "folder")
  public List<Resource> getResources()
  {
    return resources;
  }

  public void setResources(List<Resource> resources)
  {
    this.resources = resources;
  }
  
  
  
  @Override
  public String toString()
  {
    if("".equals(this.getName()))
    {
      return "/";
    }
    else
    {
      return this.getName();
    }
  }
  
  /** Two folders are equal if they have the same ID */
  @Override
  public boolean equals(Object obj)
  {
    if(obj == null)
      return false;
    
    try
    {
      Folder other = (Folder) obj;
      return this.getId() == other.id;
    }
    catch(Exception ex)
    {
      return false;
    }
  }

  @Override
  public int hashCode()
  {
    int hash = 7;
    hash = 37 * hash + (int) (this.id ^ (this.id >>> 32));
    return hash;
  }
  
  
}
